/* 
 * File:   Game.cpp
 * Author: agu
 * 
 * Created on 22 de mayo de 2014, 14:45
 */

#include "client_Texture.h"


#include "client_Game.h"
#include "client_InitializationException.h"
#include "client_Directories.h"
#include "client_AnimationPlayer.h"
#include "client_socket.h"
#include "client_thread.h"
#include <string>
#define LARGO 5
#define FPS 5

Game::Game(string name) : window(name) {
    if (!this->window.init())
        throw InitializationException("Error al iniciar al juego");
    this->renderer = SDL_CreateRenderer(window.getWindowSDL(), -1, SDL_RENDERER_ACCELERATED);
    this->running = false;
    this->recibir = true;
    SDL_SetRenderDrawColor(this->renderer, 0xFF, 0xFF, 0xFF, 0xFF);
    //Primero recibir el tile map para crear el mapa
    this->tileMap.setRenderer(this->renderer);

    this->keys = new queue<string>;

}

Game::Game(Window& windows, SDL_Renderer* renderer) {
    this->window = windows;
    this->renderer = renderer;
    this->running = false;
    this->tileMap.setRenderer(this->renderer);
    this->recibir = true;
    this->keys = new queue<string>;

}

Game::~Game() {
    this->freePlayer();
    SDL_DestroyRenderer(this->renderer);
}

void Game::run() {
    this->running = true;
    this->tileMap.setPlayerCode(this->getPlayerCode());
    this->loadGraphics();
    this->loadAudio();
//    this->music.play();
    //thread para enviar info de la tecla detectada:
    Client_thread thread = Client_thread(&this->socket);
    thread.setKeys(this->keys);
    thread.setFlag(&this->running);
    thread.iniciar(); //envia info de la tecla detectada.        
    while (this->running) {
        this->start = SDL_GetTicks();
        this->input(); //eventos tipo cerrar ventana.
        if (this->running) {
            this->recv(); //recibe tilemap.
            this->update(); // actualiza el mapa
            this->render(); //dibuja (tilemap).  
            this->fps();
        }
    }
    this->active = false;
    //join del hilo de enviar
    thread.join();
    Texture tex(this->renderer, "../Vista/img/map/background/wallFinish.png", 0, 0);
    tex.render(0, 0, window.getWidth(), window.getHeight());
    SDL_RenderPresent(this->renderer);
    SDL_Delay(4000);
    this->window.close();
}

void Game::input() {
    while (SDL_PollEvent(&this->event)) {
        this->handleEvent();
        this->updateMovements();
        //this->music.update(); Deberia ir en un hilo aparte
    }
}

void Game::handleEvent() {
    switch (this->event.type) {
        case SDL_QUIT:
            this->running = false;
            break;
        case SDL_WINDOWEVENT:
            this->window.handleEvent(this->event.window);
            break;
    }

}

void Game::render() {
    SDL_RenderClear(this->renderer);
    this->renderMap();
    this->renderPlayer();
    SDL_RenderPresent(this->renderer);
}

void Game::renderMap() {
    this->tileMap.render();
}

void Game::renderPlayer() {
    if (this->tileMap.havePlayer()) {
        if (player != NULL) {
            int posX = 0, posY = 0;
            this->tileMap.getPlayerPosition(posX, posY);
            this->player->updatePosition(posX, posY);
            this->player->render();
        }
    }

}

void Game::updateMap() {
    //Aca se actualiza el mapa, el tileString deberia cambiar
    if (!this->tileString.empty()) {
        this->tileMap.update(this->tileString);
        if (this->tileMap.haveExplotion()) {
            this->sound.play();
        }
    }    
}

void Game::updateMovements() {
    if (this->player != NULL)
        this->player->updateMovement(this->event);
}

void Game::playEffects() {
    //Aca se activan los efectos de sonido
}

void Game::update() {
    this->updateMap();
}

void Game::loadAudio() {
//    this->music.load(DIR_AUDIO + "daft.mp3");
    this->sound.load(DIR_AUDIO + "explosion.wav");
}

void Game::loadMap() {
    if (!this->tileString.empty()) {
        int size = sqrt(this->tileString.size())*32;
        this->window.setHeight(size);
        this->window.setWidth(size);
        this->tileMap.load(this->tileString);
    }

}

void Game::loadPlayer() {
    if (this->tileMap.havePlayer()) {
        int posX = 0, posY = 0;
        string pathPlayer = this->tileMap.getPlayerPath();
        this->tileMap.getPlayerPosition(posX, posY);
        this->player = new AnimationPlayer(this->renderer, pathPlayer, posX, posY);
        if (this->player != NULL)
            this->player->setQueue(keys);
    }
}

/*
 * Aca se deberia levantar el tile map
 */
void Game::loadGraphics() {
    this->loadMap();
    this->loadPlayer();
}

void Game::freePlayer() {
    if (this->player != NULL)
        delete this->player;
}

queue<string>* Game::getKeys() {
    return this->keys;
}

bool Game::isRunning() {
    return this->running;
}

void Game::setSocket(Client_socket s) {
    this->socket = s;
}

void Game::send() {
    //mientras haya mensajes para enviar, los envia
    while (!this->keys->empty()) {
        this->recibir = true;
        string buffer = this->keys->front();
        int tam = buffer.size();
        this->socket.enviar(buffer, tam);
        this->keys->pop();
    }
}

void Game::recv() {
    if (this->recibir && this->running) {
        //recibe el tamanio del tilemap
        string largoALeer;
        if (this->socket.recibir(&largoALeer, LARGO) == -1) {
        }
        int largoTileMap = stoi(largoALeer);
        //recibe un tilemap
        string tileMap;
        if (this->socket.recibir(&tileMap, largoTileMap) == -1) {            
        }
        tileMap.erase(0, 1);
        if (tileMap == "S") {
            this->running = false;
        } else {
            this->tileString = tileMap;
        }
    }
}

void Game::fps() {
    if (1000 / FPS > SDL_GetTicks() - this->start) {
        SDL_Delay(1000 / FPS - (SDL_GetTicks() - this->start));
    }
}

void Game::setInitialTileMap(const string tileMap) {
    this->tileString = tileMap;
}

void Game::setPlayerCode(const string code) {
    this->playerCode = code;
}

string Game::getPlayerCode() {
    return this->playerCode;
}